package cn.zj.note.todo;

import cn.zj.note.util.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Stream;

public class TodoManager {
    private static final String LINE_TAG = "\r\n";
    private static final String RECORD_LINE_TAG = "=====zjnotetodorecordline=====";
    private static final String RECORD_TAG = "=====zjnotetodorecord=====";
    private static final Path todoFolderPath = Paths.get("./data");
    private static final String resFileName = "data.res";
    private static final Path resourcesPath = Paths.get(todoFolderPath.toString(),resFileName);
    private static TodoManager instance;
    private TodoManager() {
        readTodos();
        readResources();
    }
    private List<Todo> todos;
    private List<String> resources;

    public static TodoManager getInstance() {
        if(instance == null) {
            instance = new TodoManager();
        }
        return instance;
    }

    public void addResource(String resName){
        resources.add(resName);
    }

    private void readTodos() {
        todos = new ArrayList<>();
        if(!Files.exists(todoFolderPath)){
            try {
                Files.createDirectory(todoFolderPath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return;
        }
        try (Stream<Path> stream = Files.list(todoFolderPath)) {
            stream.forEach(path -> {
                if(path.equals(resourcesPath)){
                    return;
                }
                try {
                    todos.add(covertTodo(Files.readAllLines(path, StandardCharsets.UTF_8)));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
            todos.sort(Comparator.comparing(Todo::getUpdateTime));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Todo covertTodo(List<String> lines) {
        Todo todo = new Todo(lines.get(0));
        todo.setStatus("true".equals(lines.get(1)));
        todo.setCreateTime(StrFmtUtil.fmtDate(lines.get(2)));
        todo.setUpdateTime(StrFmtUtil.fmtDate(lines.get(3)));
        todo.setResource(lines.get(4));
        todo.setUrl(lines.get(5));
        int initRecordLine = 0;
        for (int i = 0; i < lines.size(); i++) {
            final String tag = lines.get(i);
            if(RECORD_TAG.equals(tag)){
                initRecordLine = i;
                break;
            }
        }
        List<Record> records = new ArrayList<>();
        for (int i = initRecordLine; i < lines.size(); i = i+3) {
            final String tag = lines.get(i);
            if(!RECORD_TAG.equals(tag)){
                break;
            }
            // 2024-12-12 12:12:12
            Record record = new Record(lines.get(i+2).replace(RECORD_LINE_TAG,LINE_TAG));
            String timeStr = lines.get(i+1);
            record.setCreateTime(StrFmtUtil.fmtDate(timeStr));
            records.add(record);
        }
        todo.setRecords(records);
        return todo;
    }

    private void readResources() {
        resources = new ArrayList<>();
        if(!Files.exists(resourcesPath)){
            try {
                Files.createFile(resourcesPath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return;
        }
        try {
            List<String> lines = Files.readAllLines(resourcesPath);
            for (String line : lines) {
                if(StringUtil.isBlank(line)){
                    continue;
                }
                addResource(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public List<Todo> getTodos() {
        todos.sort(Comparator.comparing(Todo::getUpdateTime));
        Collections.reverse(todos);
        todos.sort(Comparator.comparing(Todo::isStatus));
        return todos;
    }

    public List<String> getResources(){
        return resources;
    }

    public void addTodo(Todo newTodo) {
        todos.add(newTodo);
        saveData(newTodo);
    }

    public void saveData(Todo todo){
        todo.setUpdateTime(DateUtil.curLocalDateTime());
            StringBuilder sb = new StringBuilder();
            sb.append(todo.getTitle()).append(LINE_TAG)
                    .append(todo.isStatus()).append(LINE_TAG)
                    .append(StrFmtUtil.fmtDate(todo.getCreateTime())).append(LINE_TAG)
                    .append(StrFmtUtil.fmtDate(todo.getUpdateTime())).append(LINE_TAG)
                    .append(todo.getResource()).append(LINE_TAG)
                    .append(todo.getUrl()).append(LINE_TAG);
            for (Record record : todo.getRecords()) {
                sb.append(RECORD_TAG).append(LINE_TAG)
                        .append(StrFmtUtil.fmtDate(record.getCreateTime())).append(LINE_TAG)
                        .append(record.getContent()
                                .replace("\n",RECORD_LINE_TAG)
                                .replace("\r",RECORD_LINE_TAG)
                                .replace(LINE_TAG,RECORD_LINE_TAG)).append(LINE_TAG);
            }
            String filePath = Paths.get(todoFolderPath.toString(), MD5Util.getMD5String(todo.getIdTag())).toString();
        System.out.println(filePath);
            FileUtil.writeFile(filePath, sb.toString());
    }
}
